package com.ng.desktop.view.intercambio;

import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;

import com.ng.desktop.model.Alimento;
import com.ng.desktop.model.Intercambio;
import com.ng.desktop.persistence.AlimentoPersistence;
import com.ng.desktop.persistence.IntercambioPersistence;
import com.ng.desktop.services.NGFactoryBean;
import com.ng.desktop.services.THListingService;
import com.ng.framework.persistence.NGListingBean;
import com.ng.framework.persistence.NGSearchCriteria;
import com.ng.framework.persistence.NGSearchParameter;
import com.ng.framework.persistence.NGSearchParameter.Type;
import com.ng.framework.persistence.NGSearchParameter.UnaryOperation;
import com.ng.framework.view.desktop.NGCombo;
import com.ng.framework.view.desktop.NGDualList;
import com.ng.framework.view.desktop.NGGUIUtils;

public class IntercambioFrame extends JInternalFrame implements ActionListener, ItemListener {

	private static final long serialVersionUID = -8735733767696196163L;

	private Intercambio intercambio;

	private AlimentoPersistence alimentoPersistence;
	private IntercambioPersistence intercambioPersistence;
	private THListingService thListingService;

	private NGCombo comboCategoria;
	private NGCombo comboAlimento;
	private NGDualList<NGListingBean> listIntercambio;
	private JButton buttonEditar;
	private JButton buttonCancelar;
	private JButton buttonGuardar;
	private JButton buttonVolver;

	public IntercambioFrame() {
		this.buildGui();

		this.setFrameIcon(NGGUIUtils.getImageIcon("icons/arrow-retweet.png"));
		this.setTitle("Gestión de Intercambios");
		this.setSize(new Dimension(600, 600));

		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		Dimension frameSize = this.getSize();
		if (frameSize.height > screenSize.height) {
			frameSize.height = screenSize.height;
		}
		if (frameSize.width > screenSize.width) {
			frameSize.width = screenSize.width;
		}

		this.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height - 100) / 2);

		this.setEditionMode(false);
		this.populateComboAlimento();
	}

	private void buildGui() {
		Container contentPane = this.getContentPane();

		contentPane.setLayout(new GridBagLayout());

		contentPane.add(new JLabel("Categoria:"), new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.EAST,
				GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
		contentPane.add(this.getComboCategoria(), new GridBagConstraints(1, 0, 1, 1, 1, 0, GridBagConstraints.WEST,
				GridBagConstraints.NONE, new Insets(5, 0, 5, 5), 0, 0));
		contentPane.add(new JLabel("Alimento:"), new GridBagConstraints(0, 1, 1, 1, 0, 0, GridBagConstraints.EAST,
				GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
		contentPane.add(this.getComboAlimento(), new GridBagConstraints(1, 1, 1, 1, 1, 0, GridBagConstraints.WEST,
				GridBagConstraints.NONE, new Insets(0, 0, 5, 5), 0, 0));

		contentPane.add(this.getListIntercambio(), new GridBagConstraints(0, 2, 2, 1, 1, 1, GridBagConstraints.CENTER,
				GridBagConstraints.BOTH, new Insets(0, 5, 5, 5), 0, 0));

		contentPane.add(this.createPanelButtons(), new GridBagConstraints(0, 3, 2, 1, 1, 0, GridBagConstraints.CENTER,
				GridBagConstraints.HORIZONTAL, new Insets(0, 5, 5, 5), 0, 0));

		contentPane.add(this.getButtonVolver(), new GridBagConstraints(0, 4, 2, 1, 1, 0, GridBagConstraints.EAST,
				GridBagConstraints.NONE, new Insets(0, 5, 5, 5), 0, 0));
	}

	private NGCombo getComboCategoria() {
		if (comboCategoria == null) {
			this.comboCategoria = new NGCombo();
			comboCategoria.addNGItems(getListingService().getList(THListingService.CATEGORIAS, null, null));
			comboCategoria.addItemListener(this);
			comboCategoria.setPreferredSize(new Dimension(200, comboCategoria.getPreferredSize().height));
		}
		return comboCategoria;
	}

	private THListingService getListingService() {
		if (thListingService == null) {
			thListingService = (THListingService) NGFactoryBean.getInstance().getBean("thListingService");
		}
		return thListingService;
	}

	private NGCombo getComboAlimento() {
		if (comboAlimento == null) {
			this.comboAlimento = new NGCombo();
			comboAlimento.addItemListener(this);
			comboAlimento.setPreferredSize(new Dimension(200, comboAlimento.getPreferredSize().height));
		}
		return comboAlimento;
	}

	private AlimentoPersistence getAlimentoPersistence() {
		if (alimentoPersistence == null) {
			this.alimentoPersistence = (AlimentoPersistence) NGFactoryBean.getInstance().getBean("alimentoPersistence");
		}
		return alimentoPersistence;
	}

	private NGDualList<NGListingBean> getListIntercambio() {
		if (listIntercambio == null) {
			this.listIntercambio = new NGDualList<NGListingBean>(NGListingBean.class);
		}
		return listIntercambio;
	}

	private JPanel createPanelButtons() {
		JPanel panelButtons = new JPanel(new GridBagLayout());

		panelButtons.add(this.getButtonEditar(), new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.WEST,
				GridBagConstraints.NONE, new Insets(0, 0, 0, 5), 0, 0));
		panelButtons.add(new JSeparator(JSeparator.VERTICAL), new GridBagConstraints(1, 0, 1, 1, 0, 1, GridBagConstraints.CENTER,
				GridBagConstraints.VERTICAL, new Insets(0, 0, 0, 5), 0, 0));
		panelButtons.add(this.getButtonGuardar(), new GridBagConstraints(2, 0, 1, 1, 0, 0, GridBagConstraints.WEST,
				GridBagConstraints.NONE, new Insets(0, 0, 0, 5), 0, 0));
		panelButtons.add(this.getButtonCancelar(), new GridBagConstraints(3, 0, 1, 1, 1, 0, GridBagConstraints.WEST,
				GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));

		return panelButtons;
	}

	private JButton getButtonEditar() {
		if (buttonEditar == null) {
			this.buttonEditar = NGGUIUtils.createIconButton("icons/pencil.png", this);
		}
		return buttonEditar;
	}

	private JButton getButtonGuardar() {
		if (buttonGuardar == null) {
			this.buttonGuardar = NGGUIUtils.createIconButton("icons/disk.png", this);
		}
		return buttonGuardar;
	}

	private JButton getButtonCancelar() {
		if (buttonCancelar == null) {
			this.buttonCancelar = NGGUIUtils.createIconButton("icons/cross.png", this);
		}
		return buttonCancelar;
	}

	private JButton getButtonVolver() {
		if (buttonVolver == null) {
			this.buttonVolver = NGGUIUtils.createTextButton("Volver", this);
		}
		return buttonVolver;
	}

	private void setEditionMode(boolean editionMode) {
		this.getComboCategoria().setEnabled(!editionMode);
		this.getComboAlimento().setEnabled(!editionMode);
		this.getListIntercambio().setEnabled(editionMode);
		this.getButtonEditar().setEnabled(!editionMode);
		this.getButtonGuardar().setEnabled(editionMode);
		this.getButtonCancelar().setEnabled(editionMode);
	}

	private void populateComboAlimento() {
		this.getComboAlimento().removeAllNGItems();
		this.getComboAlimento().addNGItems(this.toNgListingBeans(this.getAlimentosCategoria()));
	}

	private List<NGListingBean> toNgListingBeans(Collection<Alimento> alimentos) {
		List<NGListingBean> alimentosNgListingBean = new ArrayList<NGListingBean>();

		if (alimentos != null) {
			for (Alimento alimento : alimentos) {
				alimentosNgListingBean.add(new NGListingBean(alimento.getId(), alimento.getNombre()));
			}
		}
		return alimentosNgListingBean;
	}

	private List<Alimento> getAlimentosCategoria() {
		NGListingBean categoria = this.getComboCategoria().getSelectedNGItem(NGListingBean.class);

		NGSearchCriteria searchCriteria = new NGSearchCriteria();
		searchCriteria.addNGSearchParameter(new NGSearchParameter(Alimento.class, "categoria", String.valueOf(categoria.getId()),
				Type.INTEGER, UnaryOperation.EQUALS, true, "id"));

		return this.getAlimentoPersistence().getAll(searchCriteria);
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == this.getButtonEditar()) {
			this.setEditionMode(true);
		} else if (e.getSource() == this.getButtonGuardar()) {

			List<NGListingBean> ngListingBeans = this.getListIntercambio().getRightListElements();
			ngListingBeans.add(this.getComboAlimento().getSelectedNGItem(NGListingBean.class));

			intercambio.setAlimentos(new HashSet<Alimento>(this.toAlimentos(ngListingBeans)));

			if (intercambio.getId() == null) {
				this.getIntercambioPersistence().create(intercambio);
			} else {
				this.getIntercambioPersistence().update(intercambio);
			}

			this.setEditionMode(false);
		} else if (e.getSource() == this.getButtonCancelar()) {
			this.setEditionMode(false);
			this.populateListIntercambio();
		} else if (e.getSource() == this.getButtonVolver()) {
			this.dispose();
		}
	}

	private List<Alimento> toAlimentos(List<NGListingBean> ngListingBeans) {
		List<Alimento> alimentos = new ArrayList<Alimento>();

		if (ngListingBeans != null) {
			for (NGListingBean ngListingBean : ngListingBeans) {
				alimentos.add(this.getListingService().getHydratedBean(ngListingBean, Alimento.class));
			}
		}

		return alimentos;
	}

	private void populateListIntercambio() {
		NGListingBean alimento = this.getComboAlimento().getSelectedNGItem(NGListingBean.class);

		NGSearchCriteria searchCriteria = new NGSearchCriteria();
		searchCriteria.addNGSearchParameter(new NGSearchParameter(Intercambio.class, "alimentos",
				String.valueOf(alimento.getId()), Type.INTEGER, UnaryOperation.EQUALS, true, "id"));

		List<Intercambio> intercambios = getIntercambioPersistence().getAll(searchCriteria);

		if (CollectionUtils.isEmpty(intercambios)) {
			this.intercambio = new Intercambio();
		} else {
			this.intercambio = intercambios.get(0);
		}

		List<NGListingBean> leftListContent = new ArrayList<NGListingBean>();
		List<NGListingBean> rightListContent = new ArrayList<NGListingBean>();

		List<Alimento> alimentosCategoria = this.getAlimentosCategoria();
		for (Alimento alimentoCategoria : alimentosCategoria) {
			if (!alimentoCategoria.getId().equals(alimento.getId())
					&& (!containsAlimento(alimentoCategoria.getId(), intercambio.getAlimentos()))) {
				leftListContent.add(new NGListingBean(alimentoCategoria.getId(), alimentoCategoria.getNombre()));
			}
		}

		if (!CollectionUtils.isEmpty(intercambio.getAlimentos())) {
			for (Alimento alimentoIntercambio : intercambio.getAlimentos()) {
				if (!alimentoIntercambio.getId().equals(alimento.getId())) {
					rightListContent.add(new NGListingBean(alimentoIntercambio.getId(), alimentoIntercambio.getNombre()));
				}
			}
		}

		this.getListIntercambio().setLeftListElements(leftListContent);
		this.getListIntercambio().setRightListElements(rightListContent);
	}

	@Override
	public void itemStateChanged(ItemEvent e) {
		if (e.getStateChange() == ItemEvent.SELECTED) {
			if (e.getSource() == this.getComboCategoria()) {
				this.populateComboAlimento();
			} else if (e.getSource() == this.getComboAlimento()) {
				this.populateListIntercambio();
			}
		}
	}

	private IntercambioPersistence getIntercambioPersistence() {
		if (intercambioPersistence == null) {
			this.intercambioPersistence = (IntercambioPersistence) NGFactoryBean.getInstance().getBean("intercambioPersistence");
		}
		return intercambioPersistence;
	}

	private boolean containsAlimento(final Long alimentoId, Collection<Alimento> alimentos) {
		boolean contains = false;

		if (alimentos != null) {
			contains = CollectionUtils.find(alimentos, new Predicate() {

				@Override
				public boolean evaluate(Object object) {
					return ((Alimento) object).getId().equals(alimentoId);
				}

			}) != null;
		}

		return contains;
	}
}
